#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include "exception.h"
#include "debug.h"


void OpenConsole() {
	AllocConsole();
	SetConsoleTitleA("smse2k Debugamatron");
}

void SetConTitle(const char* msg, ...) {
	char buffer[256];
	va_list arglist;

	va_start(arglist, msg);
	vsprintf(buffer, msg, arglist);
	va_end(arglist);

	SetConsoleTitleA(buffer);
}

void __fastcall PrintFatalErrorHeader() {
	Msg("*********************************\n");
	Msg("smse2k took a shit\n");

#ifdef _WIN64
	Msg("Build: " __DATE__ __TIME__ " (x64)\n");
#else
	Msg("Build: " __DATE__ " "__TIME__ "\nReason: ");
#endif
}

// purecall override to catch stupid code
int _purecall() {
	UINT32 _ecx;

	
	// MSVC compilers: Get the class instance that caused the error to happen (almost always ecx).
	// This does NOT work for x64
#ifndef _WIN64
	__asm { mov _ecx, ecx };
#endif
	
	PrintFatalErrorHeader();
	Msg("__purecall trap hit\n");

#ifdef _WIN64
	Msg("Cannot determine the faulty class (x64 build)\n");
#else
	Msg("Problem was caused by class instance at %p\n",_ecx);
#endif

	// show an error message to end-users and terminate the program
//	FatalError("A programmer screwed up. Debug information has been output to console.\n"
//		   "Click OK to terminate the program.");
//	ExitProcess(1); // DIEEEEEEE YOUUUUUUUU
	return 0;
}


// MessageOuputFunction (goes to printf by default)
static DebugOutputFcn MessageOutputFunction = (void(*)(const char*)) printf;

void Msg(const char* msg, ...) {
	char buffer[256];
	va_list arglist;

	va_start(arglist, msg);
	vsprintf(buffer, msg, arglist);
	va_end(arglist);

	if (MessageOutputFunction)
		MessageOutputFunction(buffer);

}

void FatalError(const char* msg, ...) {
	char buffer[1027];
	va_list arglist;

	va_start(arglist, msg);
	vsprintf(buffer, msg, arglist);
	va_end(arglist);

	MessageBoxA(NULL,buffer,"smse2k has a problem",MB_OK | MB_ICONERROR);

}

int Exception(ExceptionStruct exc) {
	
	
	PrintFatalErrorHeader();
	Msg("Exception 0x%08X\n", ExceptionCode(exc));
	Msg("Exception was raised at 0x%p\n",ExceptionPC(exc));


#ifdef _WIN64
	DUMP_REGISTER(exc,"rax",REGISTER_RAX);
	DUMP_REGISTER(exc,"rbx",REGISTER_RBX);
	DUMP_REGISTER(exc,"rcx",REGISTER_RCX);
	DUMP_REGISTER(exc,"rdx",REGISTER_RDX);
	DUMP_REGISTER(exc,"rsi",REGISTER_RSI);
	DUMP_REGISTER(exc,"rdi",REGISTER_RDI);
	DUMP_REGISTER(exc,"rbp",REGISTER_RBP);
	DUMP_REGISTER(exc,"rsp",REGISTER_RSP);
	DUMP_REGISTER(exc,"r8",REGISTER_R8);
	DUMP_REGISTER(exc,"r9",REGISTER_R9);
	DUMP_REGISTER(exc,"r10",REGISTER_R10);
	DUMP_REGISTER(exc,"r11",REGISTER_R11);
	DUMP_REGISTER(exc,"r12",REGISTER_R12);
	DUMP_REGISTER(exc,"r13",REGISTER_R13);
	DUMP_REGISTER(exc,"r14",REGISTER_R14);
	DUMP_REGISTER(exc,"r15",REGISTER_R15);
#else
	DUMP_REGISTER(exc,"eax",REGISTER_EAX);
	DUMP_REGISTER(exc,"ebx",REGISTER_EBX);
	DUMP_REGISTER(exc,"ecx",REGISTER_ECX);
	DUMP_REGISTER(exc,"edx",REGISTER_EDX);
	DUMP_REGISTER(exc,"esi",REGISTER_ESI);
	DUMP_REGISTER(exc,"edi",REGISTER_EDI);
	DUMP_REGISTER(exc,"ebp",REGISTER_EBP);
	DUMP_REGISTER(exc,"esp",REGISTER_ESP);
#endif
	Msg("*********************************\n");
	

	//FatalError("Unhandled exception in smse2k core: %08X. Debug information has been output to console.\n"
	//	   "Click OK to terminate the program.");
	//ExitProcess(1);
	
	// Kill the program here
	return 0;
}

// Die() handles stuff that is unrecoverable
void Die(const char* msg, ...) {
	char buffer[256];
	va_list arglist;

	va_start(arglist, msg);
	vsprintf(buffer, msg, arglist);
	va_end(arglist);

	if (MessageOutputFunction)
		MessageOutputFunction(buffer);

	Msg("Die() called, exiting\n");
	FatalError("WELCOME TO DIE !!\n\nDebug information has been output to console.\n"
		   "Click OK to terminate the program.");
	ExitProcess(1);

	// Thread never returns
	while (1);
}

// Setup the message output function
void __fastcall SetMessageOutput(DebugOutputFcn fcn) {
	MessageOutputFunction = fcn;
}